/*
 * rfc1055.c
 *
 * Created: 2012.10.26. 17:37:35
 *  Author: Tibor
 */ 

#define END 0xc0  /*0300 indicates end of packet */
#define ESC 0xdb   /*0333 indicates byte stuffing */
#define ESC_END 0xdc /*0334 ESC ESC_END means END data byte */
#define ESC_ESC 0xdd /*0335 ESC ESC_ESC means ESC data byte */


typedef unsigned char (*ReceiveCharType)(void);

/* RECV_PACKET: receives a packet into the buffer located at "p".
*      If more than len bytes are received, the packet will
*      be truncated.
*      Returns the number of bytes stored in the buffer.
*/
int recPacket(char *p, int len, ReceiveCharType recv_char){
    unsigned char c;
    int received = 0;

    /* sit in a loop reading bytes until we put together
    * a whole packet.
    * Make sure not to copy them into the packet if we
    * run out of room.
    */
	while(1) {
        /* get a character to process
        */
        c = recv_char();

        /* handle bytestuffing if necessary */
        switch(c) {

			/* if it's an END character then we're done with
			* the packet
			*/
			case END:
				/* a minor optimization: if there is no
				* data in the packet, ignore it. This is
				* meant to avoid bothering IP with all
				* the empty packets generated by the
				* duplicate END characters which are in
				* turn sent to try to detect line noise.
				*/
				if(received){
						return received;
				}					
				else{
						break;
				}					

			/* if it's the same code as an ESC character, wait
			* and get another character and then figure out
			* what to store in the packet based on that.
			*/
			case ESC:
				c = recv_char();
				/* if "c" is not one of these two, then we
				* have a protocol violation.  The best bet
				* seems to be to leave the byte alone and
				* just stuff it into the packet
				*/
				switch(c) {
					case ESC_END:
						c = END;
						break;
					case ESC_ESC:
						c = ESC;
						break;
				}

            /* here we fall into the default handler and let
            * it store the character for us
            */
            default:
                if(received < len){
                    p[received++] = c;
				}else{
					return received;
				}				
		}
	}
}
